<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js">var GlobalEventDispatcher = require(&quot;./event/GlobalEventDispatcher&quot;);

var CanvasPainter = require(&quot;./canvas/CanvasPainter&quot;);

var GlobalAnimationMgr = require(&quot;./animation/GlobalAnimationMgr&quot;);

var DomEventInterceptor = require(&quot;./event/DomEventInterceptor&quot;);

var Storage = require(&quot;./Storage&quot;);

var textContain = require(&quot;./utils/contain/text&quot;);

var guid = require(&quot;./utils/guid&quot;);

var env = require(&quot;./utils/env&quot;);

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(&quot;Cannot call a class as a function&quot;); } }

function _defineProperties(target, props) { for (var i = 0; i &lt; props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (&quot;value&quot; in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

<span id='qrenderer-core-QuarkRenderer'>/**
</span> * @class qrenderer.core.QuarkRenderer
 * QuarkRenderer, a high performance 2d drawing library.
 * Class QuarkRenderer is the global entry, every time you call qrenderer.init() will 
 * create an instance of QuarkRenderer class, each instance has an unique id.
 * 
 * QuarkRenderer 是一款高性能的 2d 渲染引擎。
 * QuarkRenderer 类是全局入口，每次调用 qrenderer.init() 会创建一个实例，
 * 每个 QuarkRenderer 实例有自己唯一的 ID。
 * 
 * @docauthor 大漠穷秋 damoqiongqiu@126.com
 */
if (!env.canvasSupported) {
  throw new Error(&quot;Need Canvas Environment.&quot;);
}

var painterMap = {
  canvas: CanvasPainter
}; // QuarkRenderer 实例map索引，浏览器中同一个 window 下的 QuarkRenderer 实例都存在这里。

var instances = {};
<span id='qrenderer-core-QuarkRenderer-property-version'>/**
</span> * @property {String}
 */

var version = &#39;1.0.26&#39;;
<span id='qrenderer-core-QuarkRenderer-method-qrenderer'>/**
</span> * @method qrenderer.init()
 * Global entry for creating a qrenderer instance.
 * 
 * 全局总入口，创建 QuarkRenderer 的实例。
 * 
 * @param {HTMLDomElement|Canvas|Context} host 
 * This can be a HTMLDomElement like a DIV, or a Canvas instance, 
 * or Context for Wechat mini-program.
 * 
 * 此属性可以是 HTMLDomElement ，比如 DIV 标签；也可以是 Canvas 实例；或者是 Context 实例，因为在某些
 * 运行环境中，不能获得 Canvas 实例的引用，只能获得 Context。
 * @param {Object} [options]
 * @param {String} [options.renderer=&#39;canvas&#39;] &#39;canvas&#39; or &#39;svg&#39;
 * @param {Number} [options.devicePixelRatio]
 * @param {Number|String} [options.width] Can be &#39;auto&#39; (the same as null/undefined)
 * @param {Number|String} [options.height] Can be &#39;auto&#39; (the same as null/undefined)
 * @return {QuarkRenderer}
 */

function init(host, options) {
  var qr = new QuarkRenderer(host, options);
  instances[qr.id] = qr;
  return qr;
}
<span id='qrenderer-core-QuarkRenderer-method-dispose'>/**
</span> * TODO: 不要export这个全局函数看起来也没有问题。
 * Dispose qrenderer instance
 * @param {QuarkRenderer} qr
 */


function dispose(qr) {
  if (qr) {
    qr.dispose();
  } else {
    for (var key in instances) {
      if (instances.hasOwnProperty(key)) {
        instances[key].dispose();
      }
    }

    instances = {};
  }

  return this;
}
<span id='qrenderer-core-QuarkRenderer-static-method-getInstance'>/**
</span> * @static
 * @method getInstance
 * Get qrenderer instance by id.
 * @param {String} id
 * @return {QuarkRenderer}
 */


function getInstance(id) {
  return instances[id];
}

function registerPainter(name, PainterClass) {
  painterMap[name] = PainterClass;
}
<span id='qrenderer-core-QuarkRenderer-method-constructor'>/**
</span> * @method constructor QuarkRenderer
 * @param {String} id
 * @param {HTMLElement} host
 * @param {Object} [options]
 * @param {String} [options.renderer=&#39;canvas&#39;] &#39;canvas&#39; or &#39;svg&#39;
 * @param {Number} [options.devicePixelRatio]
 * @param {Number} [options.width] Can be &#39;auto&#39; (the same as null/undefined)
 * @param {Number} [options.height] Can be &#39;auto&#39; (the same as null/undefined)
 * @return {QuarkRenderer}
 */


var QuarkRenderer =
/*#__PURE__*/
function () {
  function QuarkRenderer(host) {
    var options = arguments.length &gt; 1 &amp;&amp; arguments[1] !== undefined ? arguments[1] : {};

    _classCallCheck(this, QuarkRenderer);

<span id='qrenderer-core-QuarkRenderer-property-id'>    /**
</span>     * @private
     * @property {String} id
     */
    this.id = guid();
<span id='qrenderer-core-QuarkRenderer-property-host'>    /**
</span>     * @property {HTMLDomElement|Canvas|Context} host 
     * This can be a HTMLDomElement like a DIV, or a Canvas instance, 
     * or Context for Wechat mini-program.
     * 
     * 此属性可以是 HTMLDomElement ，比如 DIV 标签；也可以是 Canvas 实例；或者是 Context 实例，因为在某些
     * 运行环境中，不能获得 Canvas 实例的引用，只能获得 Context。
     */

    this.host = host;
    var self = this;
<span id='qrenderer-core-QuarkRenderer-property-storage'>    /**
</span>     * @private
     * @property {Storage} storage
     */

    this.storage = new Storage(); //根据参数创建不同类型的 Painter 实例。

    var rendererType = options.renderer;

    if (!rendererType || !painterMap[rendererType]) {
      rendererType = &#39;canvas&#39;;
    }

    this.painter = new painterMap[rendererType](this.host, this.storage, options, this.id); //利用代理拦截 DOM 事件，转发到 QuarkRenderer 自己封装的事件机制。

    var eventInterceptor = null;

    if (typeof this.host.moveTo !== &#39;function&#39;) {
      if (!env.node &amp;&amp; !env.worker &amp;&amp; !env.wxa) {
        eventInterceptor = new DomEventInterceptor(this.painter.getHost());
      }
    } else {
      // host is Context instance, override function.
      textContain.$override(&#39;measureText&#39;, function (text, font) {
        self.font = font || textContain.DEFAULT_FONT;
        return self.host.measureText(text);
      });
    }
<span id='qrenderer-core-QuarkRenderer-property-eventDispatcher'>    /**
</span>     * @private
     * @property {GlobalEventDispatcher} eventDispatcher
     * QuarkRenderer 自己封装的事件机制，这是画布内部的事件系统。
     */


    this.eventDispatcher = new GlobalEventDispatcher(this.storage, this.painter, eventInterceptor, this.painter.root);
<span id='qrenderer-core-QuarkRenderer-property-globalAnimationMgr'>    /**
</span>     * @property {GlobalAnimationMgr}
     * 利用 GlobalAnimationMgr 的 frame 事件刷新画布上的元素。
     */

    this.globalAnimationMgr = new GlobalAnimationMgr();
    this.globalAnimationMgr.on(&quot;frame&quot;, function () {
      self.flush();
    });
    this.globalAnimationMgr.start();
<span id='qrenderer-core-QuarkRenderer-property-_needRefresh'>    /**
</span>     * @property {boolean}
     * @private
     */

    this._needRefresh = false;
  }
<span id='qrenderer-core-QuarkRenderer-method-'>  /**
</span>   * @method
   * 添加元素
   * @param  {qrenderer/Element} el
   */


  _createClass(QuarkRenderer, [{
    key: &quot;add&quot;,
    value: function add(el) {
      el.__qr = this;
      this.storage.addToRoot(el);
      this.refresh();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * 删除元素
     * @param  {qrenderer/Element} el
     */

  }, {
    key: &quot;remove&quot;,
    value: function remove(el) {
      this.storage.delFromRoot(el);
      el.__qr = null;
      this.refresh();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Perform refresh operation, this method will be called by window.requestAnimationFrame contantly, 
     * if there is no elment need to be repaint, this method just do nothing. Please do NOT call this 
     * method directly.
     * 
     * 
     * 刷新 canvas 画面，此方法会在 window.requestAnimationFrame 方法中被不断调用，如果没有元素需要被重绘，
     * 这个方法什么都不做。请不要直接调用此方法。
     */

  }, {
    key: &quot;flush&quot;,
    value: function flush() {
      if (this._needRefresh) {
        //try refreshing all elements
        // Clear needsRefresh ahead to avoid something wrong happens in refresh
        // Or it will cause qrenderer refreshes again and again.
        this._needRefresh = this._needRefreshHover = false;
        this.painter.refresh &amp;&amp; this.painter.refresh(); // Avoid trigger qr.refresh in Element#beforeUpdate hook

        this._needRefresh = this._needRefreshHover = false;
        this.trigger(&#39;rendered&#39;);
      }

      if (this._needRefreshHover) {
        //only try refreshing hovered elements
        this._needRefresh = this._needRefreshHover = false;
        this.painter.refreshHover &amp;&amp; this.painter.refreshHover();
        this._needRefresh = this._needRefreshHover = false;
        this.trigger(&#39;rendered&#39;);
      }
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Mark and repaint the canvas in the next frame of browser
     */

  }, {
    key: &quot;refresh&quot;,
    value: function refresh() {
      this._needRefresh = true;
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * 与 Hover 相关的6个方法用来处理浮动层，当鼠标悬停在 canvas 中的元素上方时，可能会需要
     * 显示一些浮动的层来展现一些特殊的数据。
     * TODO:这里可能有点问题，Hover 一词可能指的是遮罩层，而不是浮动层，如果确认是遮罩，考虑
     * 把这里的 API 单词重构成 Mask。
     * 
     * Add element to hover layer
     * @param  {Element} el
     * @param {Object} style
     */

  }, {
    key: &quot;addHover&quot;,
    value: function addHover(el, style) {
      if (this.painter.addHover) {
        var elMirror = this.painter.addHover(el, style);
        this.refreshHover();
        return elMirror;
      }
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Remove element from hover layer
     * @param  {Element} el
     */

  }, {
    key: &quot;removeHover&quot;,
    value: function removeHover(el) {
      if (this.painter.removeHover) {
        this.painter.removeHover(el);
        this.refreshHover();
      }
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Find hovered element
     * @param {Number} x
     * @param {Number} y
     * @return {Object} {target, topTarget}
     */

  }, {
    key: &quot;findHover&quot;,
    value: function findHover(x, y) {
      return this.eventDispatcher.findHover(x, y);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Clear all hover elements in hover layer
     * @param  {Element} el
     */

  }, {
    key: &quot;clearHover&quot;,
    value: function clearHover() {
      if (this.painter.clearHover) {
        this.painter.clearHover();
        this.refreshHover();
      }
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Refresh hover in next frame
     */

  }, {
    key: &quot;refreshHover&quot;,
    value: function refreshHover() {
      this._needRefreshHover = true;
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Resize the canvas.
     * Should be invoked when container size is changed
     * @param {Object} [options]
     * @param {Number|String} [options.width] Can be &#39;auto&#39; (the same as null/undefined)
     * @param {Number|String} [options.height] Can be &#39;auto&#39; (the same as null/undefined)
     */

  }, {
    key: &quot;resize&quot;,
    value: function resize(options) {
      options = options || {};
      this.painter.resize(options.width, options.height);
      this.eventDispatcher.resize();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Get container width
     */

  }, {
    key: &quot;getWidth&quot;,
    value: function getWidth() {
      return this.painter.getWidth();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Get container height
     */

  }, {
    key: &quot;getHeight&quot;,
    value: function getHeight() {
      return this.painter.getHeight();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @private
     * @method
     * Change configuration of layer
     * @param {String} qLevel
     * @param {Object} [config]
     * @param {String} [config.clearColor=0] Clear color
     * @param {String} [config.motionBlur=false] If enable motion blur
     * @param {Number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer
    */

  }, {
    key: &quot;configLayer&quot;,
    value: function configLayer(qLevel, config) {
      if (this.painter.configLayer) {
        this.painter.configLayer(qLevel, config);
      }

      this.refresh();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Set background color
     * @param {String} backgroundColor
     */

  }, {
    key: &quot;setBackgroundColor&quot;,
    value: function setBackgroundColor(backgroundColor) {
      if (this.painter.setBackgroundColor) {
        this.painter.setBackgroundColor(backgroundColor);
      }

      this.refresh();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Converting a path to image.
     * It has much better performance of drawing image rather than drawing a vector path.
     * @param {graphic/Path} e
     * @param {Number} width
     * @param {Number} height
     */

  }, {
    key: &quot;pathToImage&quot;,
    value: function pathToImage(e, dpr) {
      return this.painter.pathToImage(e, dpr);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Set default cursor
     * @param {String} [cursorStyle=&#39;move&#39;]
     */

  }, {
    key: &quot;setCursorStyle&quot;,
    value: function setCursorStyle(cursorStyle) {
      this.eventDispatcher.setCursorStyle(cursorStyle);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Bind event
     *
     * @param {String} eventName Event name
     * @param {Function} eventDispatcher Handler function
     * @param {Object} [context] Context object
     */

  }, {
    key: &quot;on&quot;,
    value: function on(eventName, eventDispatcher, context) {
      this.eventDispatcher.on(eventName, eventDispatcher, context);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Unbind event
     * @param {String} eventName Event name
     * @param {Function} [eventDispatcher] Handler function
     */

  }, {
    key: &quot;off&quot;,
    value: function off(eventName, eventDispatcher) {
      this.eventDispatcher.off(eventName, eventDispatcher);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Trigger event manually
     *
     * @param {String} eventName Event name
     * @param {event=} event Event object
     */

  }, {
    key: &quot;trigger&quot;,
    value: function trigger(eventName, event) {
      this.eventDispatcher.trigger(eventName, event);
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Clear all objects and the canvas.
     */

  }, {
    key: &quot;clear&quot;,
    value: function clear() {
      this.storage.delFromRoot();
      this.painter.clear();
    }
<span id='qrenderer-core-QuarkRenderer-method-'>    /**
</span>     * @method
     * Dispose self.
     */

  }, {
    key: &quot;dispose&quot;,
    value: function dispose() {
      this.globalAnimationMgr.clear();
      this.storage.dispose();
      this.painter.dispose();
      this.eventDispatcher.dispose();
      this.globalAnimationMgr = null;
      this.storage = null;
      this.painter = null;
      this.eventDispatcher = null;
      delete instances[this.id];
    }
  }]);

  return QuarkRenderer;
}(); // ---------------------------
// Events of qrenderer instance.
// ---------------------------

<span id='qrenderer-core-QuarkRenderer-event-onclick'>/**
</span> * @event onclick
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmouseover'>/**
</span> * @event onmouseover
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmouseout'>/**
</span> * @event onmouseout
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmousemove'>/**
</span> * @event onmousemove
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmousewheel'>/**
</span> * @event onmousewheel
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmousedown'>/**
</span> * @event onmousedown
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onmouseup'>/**
</span> * @event onmouseup
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondrag'>/**
</span> * @event ondrag
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondragstart'>/**
</span> * @event ondragstart
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondragend'>/**
</span> * @event ondragend
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondragenter'>/**
</span> * @event ondragenter
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondragleave'>/**
</span> * @event ondragleave
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondragover'>/**
</span> * @event ondragover
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-ondrop'>/**
</span> * @event ondrop
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onpagemousemove'>/**
</span> * @event onpagemousemove
 * @param {Function} null
 */

<span id='qrenderer-core-QuarkRenderer-event-onpagemouseup'>/**
</span> * @event onpagemouseup
 * @param {Function} null
 */


exports.version = version;
exports.init = init;
exports.dispose = dispose;
exports.getInstance = getInstance;
exports.registerPainter = registerPainter;</pre>
</body>
</html>
